//备注：拷贝代码请加上作者信息
//作者：王海涛
//邮箱：1126471088@qq.com
//版本：V0.2.1
#include "dma_bsp.h"
#include "string.h"

/*DMA总管理结构体*/
typedef struct
{
    WHT_DMA_enum Name;        //DMA通道名字
    WHT_DMA_Info_t Info;      //所有标志,提供给外部
    void (*IT_Callback)(void);//通道回调函数
}WHT_Data_t;


static WHT_Data_t WHT_DMA1_Channel_1 = {.Name = (WHT_DMA_enum)DMA1_Channel1_BASE};
static WHT_Data_t WHT_DMA1_Channel_2 = {.Name = (WHT_DMA_enum)DMA1_Channel2_BASE};
static WHT_Data_t WHT_DMA1_Channel_3 = {.Name = (WHT_DMA_enum)DMA1_Channel3_BASE};
static WHT_Data_t WHT_DMA1_Channel_4 = {.Name = (WHT_DMA_enum)DMA1_Channel4_BASE};
static WHT_Data_t WHT_DMA1_Channel_5 = {.Name = (WHT_DMA_enum)DMA1_Channel5_BASE};
static WHT_Data_t WHT_DMA1_Channel_6 = {.Name = (WHT_DMA_enum)DMA1_Channel6_BASE};
static WHT_Data_t WHT_DMA1_Channel_7 = {.Name = (WHT_DMA_enum)DMA1_Channel7_BASE};
static WHT_Data_t WHT_DMA2_Channel_1 = {.Name = (WHT_DMA_enum)DMA2_Channel1_BASE};
static WHT_Data_t WHT_DMA2_Channel_2 = {.Name = (WHT_DMA_enum)DMA2_Channel2_BASE};
static WHT_Data_t WHT_DMA2_Channel_3 = {.Name = (WHT_DMA_enum)DMA2_Channel3_BASE};
static WHT_Data_t WHT_DMA2_Channel_4 = {.Name = (WHT_DMA_enum)DMA2_Channel4_BASE};
static WHT_Data_t WHT_DMA2_Channel_5 = {.Name = (WHT_DMA_enum)DMA2_Channel5_BASE};

#define WHT_DMA     ((WHT_Data_t*)config->Private_Data)//简化操作


/*DMA中断优先级配置*/
static void NVIC_Config_uration(unsigned char NVIC_IRQChannel)
{
    NVIC_InitTypeDef NVIC_InitStruct;

    /* 嵌套向量中断控制器组选择 */
    //NVIC_PriorityGroupConfig(NVIC_PriorityGroup_4);

    /* 配置中断源 */
    NVIC_InitStruct.NVIC_IRQChannel = NVIC_IRQChannel;
    /* 抢断优先级*/
    NVIC_InitStruct.NVIC_IRQChannelPreemptionPriority = 15;
    /* 子优先级 */
    NVIC_InitStruct.NVIC_IRQChannelSubPriority = 0;
    /* 使能中断 */
    NVIC_InitStruct.NVIC_IRQChannelCmd = ENABLE;
    /* 初始化配置NVIC */
    NVIC_Init(&NVIC_InitStruct);
}
/*DMA注册*/
static ErrorStatus WHT_DMA_BSP_Register(const WHT_DMA_Config_t* config)
{
    if ((WHT_DMA != NULL) && (config->Info != NULL))//之前注册过了
        return SUCCESS;
    
    switch ((unsigned int)config->Name)
    {
    case DMA1_Channel1_BASE:((WHT_DMA_Config_t*)config)->Private_Data = &WHT_DMA1_Channel_1; NVIC_Config_uration(DMA1_Channel1_IRQn); break;
    case DMA1_Channel2_BASE:((WHT_DMA_Config_t*)config)->Private_Data = &WHT_DMA1_Channel_2; NVIC_Config_uration(DMA1_Channel2_IRQn); break;
    case DMA1_Channel3_BASE:((WHT_DMA_Config_t*)config)->Private_Data = &WHT_DMA1_Channel_3; NVIC_Config_uration(DMA1_Channel3_IRQn); break;
    case DMA1_Channel4_BASE:((WHT_DMA_Config_t*)config)->Private_Data = &WHT_DMA1_Channel_4; NVIC_Config_uration(DMA1_Channel4_IRQn); break;
    case DMA1_Channel5_BASE:((WHT_DMA_Config_t*)config)->Private_Data = &WHT_DMA1_Channel_5; NVIC_Config_uration(DMA1_Channel5_IRQn); break;
    case DMA1_Channel6_BASE:((WHT_DMA_Config_t*)config)->Private_Data = &WHT_DMA1_Channel_6; NVIC_Config_uration(DMA1_Channel6_IRQn); break;
    case DMA1_Channel7_BASE:((WHT_DMA_Config_t*)config)->Private_Data = &WHT_DMA1_Channel_7; NVIC_Config_uration(DMA1_Channel7_IRQn); break;
#ifdef STM32F10X_HD
    case DMA2_Channel1_BASE:((WHT_DMA_Config_t*)config)->Private_Data = &WHT_DMA2_Channel_1; NVIC_Config_uration(DMA2_Channel1_IRQn); break;
    case DMA2_Channel2_BASE:((WHT_DMA_Config_t*)config)->Private_Data = &WHT_DMA2_Channel_2; NVIC_Config_uration(DMA2_Channel2_IRQn); break;
    case DMA2_Channel3_BASE:((WHT_DMA_Config_t*)config)->Private_Data = &WHT_DMA2_Channel_3; NVIC_Config_uration(DMA2_Channel3_IRQn); break;
    case DMA2_Channel4_BASE:((WHT_DMA_Config_t*)config)->Private_Data = &WHT_DMA2_Channel_4; NVIC_Config_uration(DMA2_Channel4_5_IRQn); break;
    case DMA2_Channel5_BASE:((WHT_DMA_Config_t*)config)->Private_Data = &WHT_DMA2_Channel_5; NVIC_Config_uration(DMA2_Channel4_5_IRQn); break;
#endif /* STM32F10X_HD */
    default:return ERROR;
    }

    WHT_DMA->Name = config->Name;
    ((WHT_DMA_Config_t*)config)->Info = &WHT_DMA->Info;
    WHT_DMA->Info.Mount_Count++;
    RCC_AHBPeriphClockCmd(config->Name >= Source_SPI_I2S3_RX ? RCC_AHBPeriph_DMA2 : RCC_AHBPeriph_DMA1, ENABLE);//Open DMA Clock For AHB
    return SUCCESS;
}
/*DMA配置*/
static void WHT_DMA_BSP_Config(const WHT_DMA_Config_t* config)
{
    if ((WHT_DMA == NULL) || (config->Info == NULL))
        return;

    WHT_DMA->Info.State = TRx_TS;
    WHT_DMA->IT_Callback = config->IT_Callback;
    
    DMA_DeInit((DMA_Channel_TypeDef*)WHT_DMA->Name);                                           //Reset DMA
    DMA_Init((DMA_Channel_TypeDef*)WHT_DMA->Name, ((WHT_DMA_Config_t*)config)->DMA_InitStruct);//Init Config DMA Channel
    if (config->DMA_InitStruct->DMA_Mode == DMA_Mode_Circular)                                 //循环传输模式
    {
        DMA_ITConfig((DMA_Channel_TypeDef*)WHT_DMA->Name, DMA_IT_TC | DMA_IT_HT, DISABLE);     //Off TC HT DMA Interrupt
        DMA_ITConfig((DMA_Channel_TypeDef*)WHT_DMA->Name, DMA_IT_TE, ENABLE);                  //Open TE DMA Interrupt
    }
    else
        DMA_ITConfig((DMA_Channel_TypeDef*)WHT_DMA->Name, DMA_IT_TC | DMA_IT_HT | DMA_IT_TE, ENABLE);//open All DMA Interrupt
    
    DMA_Cmd((DMA_Channel_TypeDef*)WHT_DMA->Name, ENABLE);                                            //Open DMA Channel
}


/*DMA获取当前数据个数*/
static unsigned short WHT_DMA_BSP_Get_Curr_Data_Count(const WHT_DMA_Config_t* config)
{
    if (WHT_DMA == NULL)
        return (unsigned short)65535;
    else
        return DMA_GetCurrDataCounter((DMA_Channel_TypeDef*)WHT_DMA->Name);
}
/*DMA关闭*/
static void WHT_DMA_BSP_Close(const WHT_DMA_Config_t* config)
{
    if (WHT_DMA == NULL)
        return;

    DMA_Cmd((DMA_Channel_TypeDef*)WHT_DMA->Name, DISABLE);
    WHT_DMA->Info.State = TRx_TC;
    WHT_DMA->Info.BSP_Mutex = RESET;
}


/*DMA检查空闲通道并上锁*/
static ErrorStatus WHT_DMA_BSP_Lock_Idle_Channel(const WHT_DMA_Config_t* config)
{
    unsigned char Number;
    WHT_Data_t* DMA_Channel[] =
    {
        &WHT_DMA1_Channel_1,
        &WHT_DMA1_Channel_2,
        &WHT_DMA1_Channel_3,
        &WHT_DMA1_Channel_4,
        &WHT_DMA1_Channel_5,
        &WHT_DMA1_Channel_6,
        &WHT_DMA1_Channel_7,
#ifdef STM32F10X_HD
        &WHT_DMA2_Channel_1,
        &WHT_DMA2_Channel_2,
        &WHT_DMA2_Channel_3,
        &WHT_DMA2_Channel_4,
        &WHT_DMA2_Channel_5,
#endif /* STM32F10X_HD */
    };

    for (Number = 0; Number < sizeof(DMA_Channel) / sizeof(DMA_Channel[0]); Number++)//寻找未被注册过并且未使用过的
    {
        if ((DMA_Channel[Number]->Info.Mount_Count == RESET) && (DMA_Channel[Number]->Info.BSP_Mutex == RESET))
        {
            DMA_Channel[Number]->Info.BSP_Mutex = SET;
            goto Game_Over;
        }
    }
    for (Number = 0; Number < sizeof(DMA_Channel) / sizeof(DMA_Channel[0]); Number++)//寻找所有的
    {
        if (DMA_Channel[Number]->Info.BSP_Mutex == RESET)
        {
            DMA_Channel[Number]->Info.BSP_Mutex = SET;
            goto Game_Over;
        }
    }
    return ERROR;

    Game_Over:
        DMA_Channel[Number]->Info.Mount_Count++;//由调用者释放!!!
        ((WHT_DMA_Config_t*)config)->Name = DMA_Channel[Number]->Name;
        ((WHT_DMA_Config_t*)config)->IT_Callback = NULL;
        ((WHT_DMA_Config_t*)config)->Info = &DMA_Channel[Number]->Info;
        ((WHT_DMA_Config_t*)config)->Private_Data = DMA_Channel[Number];
        
        RCC_AHBPeriphClockCmd(config->Name >= Source_SPI_I2S3_RX ? RCC_AHBPeriph_DMA2 : RCC_AHBPeriph_DMA1, ENABLE);//Open DMA Clock For AHB
        switch ((unsigned int)config->Name)
        {
        case DMA1_Channel1_BASE:NVIC_Config_uration(DMA1_Channel1_IRQn); break;
        case DMA1_Channel2_BASE:NVIC_Config_uration(DMA1_Channel2_IRQn); break;
        case DMA1_Channel3_BASE:NVIC_Config_uration(DMA1_Channel3_IRQn); break;
        case DMA1_Channel4_BASE:NVIC_Config_uration(DMA1_Channel4_IRQn); break;
        case DMA1_Channel5_BASE:NVIC_Config_uration(DMA1_Channel5_IRQn); break;
        case DMA1_Channel6_BASE:NVIC_Config_uration(DMA1_Channel6_IRQn); break;
        case DMA1_Channel7_BASE:NVIC_Config_uration(DMA1_Channel7_IRQn); break;
        #ifdef STM32F10X_HD
        case DMA2_Channel1_BASE:NVIC_Config_uration(DMA2_Channel1_IRQn); break;
        case DMA2_Channel2_BASE:NVIC_Config_uration(DMA2_Channel2_IRQn); break;
        case DMA2_Channel3_BASE:NVIC_Config_uration(DMA2_Channel3_IRQn); break;
        case DMA2_Channel4_BASE:NVIC_Config_uration(DMA2_Channel4_5_IRQn); break;
        case DMA2_Channel5_BASE:NVIC_Config_uration(DMA2_Channel4_5_IRQn); break;
        #endif /* STM32F10X_HD */
        }
        return SUCCESS;
}

/*DMA内存拷贝*/
void WHT_DMA_BSP_Memcpy(void* _Dst, void const* _Src, unsigned int _Size)
{
    WHT_DMA_Config_t Config;
    unsigned int Data_Size_4x_Number;

	if (_Size > 65535 * sizeof(unsigned int) || (_Size < sizeof(unsigned int)))//for max 262140 Byte
	{
		memcpy(_Dst, _Src, _Size);
		return;
	}
    if (WHT_DMA_BSP_Lock_Idle_Channel(&Config) == ERROR)
    {
        memcpy(_Dst, _Src, _Size);
        return;
    }

	Data_Size_4x_Number = _Size >> 2;//4倍的个数
	if (_Size & 0x03)                //4倍的余数
		memcpy(((unsigned int*)_Dst) + Data_Size_4x_Number, ((unsigned int*)_Src) + Data_Size_4x_Number, _Size & 0x03);
	
 	DMA_InitTypeDef DMA_InitStruct =
	{
		.DMA_PeripheralBaseAddr = (unsigned int)_Dst,         //目的基地址
		.DMA_MemoryBaseAddr     = (unsigned int)_Src,         //源基地址
		.DMA_DIR                = DMA_DIR_PeripheralDST,      //M->M
		.DMA_BufferSize         = Data_Size_4x_Number,        //传输个数
		.DMA_PeripheralInc      = DMA_PeripheralInc_Enable,   //目的地址递增
		.DMA_MemoryInc          = DMA_MemoryInc_Enable,       //源地址递增
		.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Word,//目的数据大小为字节
		.DMA_MemoryDataSize     = DMA_MemoryDataSize_Word,    //源数据大小为字节
		.DMA_Mode               = DMA_Mode_Normal,            //单次传输模式
		.DMA_Priority           = DMA_Priority_Low,           //优先级最低
		.DMA_M2M                = DMA_M2M_Enable,             //内存到内存模式
	};

    Config.Info->State = TRx_TS;
    Config.Info->Mount_Count--;//这里给它手动减去

    DMA_Init((DMA_Channel_TypeDef*)Config.Name, &DMA_InitStruct);                  //Init Config DMA Channel
    DMA_ITConfig((DMA_Channel_TypeDef*)Config.Name, DMA_IT_TC | DMA_IT_TE, ENABLE);//Open TC TE DMA Interrupt
    DMA_Cmd((DMA_Channel_TypeDef*)Config.Name, ENABLE);                            //Open DMA Channel
}
/*全局常量*/
const WHT_DMA_BSP_t WHT_DMA_BSP =
{
    .WHT_Register            = WHT_DMA_BSP_Register,
    .WHT_Config              = WHT_DMA_BSP_Config,
    .WHT_Get_Curr_Data_Count = WHT_DMA_BSP_Get_Curr_Data_Count,
    .WHT_Close               = WHT_DMA_BSP_Close,
};



/*DMA中断回调函数*/
static void WHT_DMA_BSP_Channel_IRQHandler(WHT_Data_t* dma_channel, unsigned int dma_it_tc, unsigned int dma_it_te, unsigned int dma_it_ht)
{
    if (DMA_GetITStatus(dma_it_tc | dma_it_te) == SET)//对于向外设发送数据,注意最后一个数据此时在发送过程中
    {
        DMA_Cmd((DMA_Channel_TypeDef*)dma_channel->Name, DISABLE);
        dma_channel->Info.State = DMA_GetITStatus(dma_it_te) == SET ? TRx_TE : TRx_TC;
        if (dma_channel->IT_Callback != NULL)
        {
            dma_channel->IT_Callback();
            dma_channel->IT_Callback = NULL;
        }
        DMA_ClearITPendingBit(dma_it_tc | dma_it_ht | dma_it_te);
        dma_channel->Info.BSP_Mutex = RESET;//要让调用者上锁和解锁*************由于有回调函数可以自解锁*************************************
    }
    else// if (DMA_GetITStatus(dma_it_ht) == SET)
    {
        DMA_ClearITPendingBit(dma_it_ht);
        dma_channel->Info.State = TRx_HT;//解决传送几个字节后导致传输过半把传输完成的中断标志位给清掉
    }
}

/*DMA1通道1中断服务程序*/
void DMA1_Channel1_IRQHandler(void)
{
    WHT_DMA_BSP_Channel_IRQHandler(&WHT_DMA1_Channel_1, DMA1_IT_TC1, DMA1_IT_TE1, DMA1_IT_HT1);
}
/*DMA1通道2中断服务程序*/
void DMA1_Channel2_IRQHandler(void)
{
    WHT_DMA_BSP_Channel_IRQHandler(&WHT_DMA1_Channel_2, DMA1_IT_TC2, DMA1_IT_TE2, DMA1_IT_HT2);
}
/*DMA1通道3中断服务程序*/
void DMA1_Channel3_IRQHandler(void)
{
    WHT_DMA_BSP_Channel_IRQHandler(&WHT_DMA1_Channel_3, DMA1_IT_TC3, DMA1_IT_TE3, DMA1_IT_HT3);
}
/*DMA1通道4中断服务程序*/
void DMA1_Channel4_IRQHandler(void)
{
    WHT_DMA_BSP_Channel_IRQHandler(&WHT_DMA1_Channel_4, DMA1_IT_TC4, DMA1_IT_TE4, DMA1_IT_HT4);
}
/*DMA1通道5中断服务程序*/
void DMA1_Channel5_IRQHandler(void)
{
    WHT_DMA_BSP_Channel_IRQHandler(&WHT_DMA1_Channel_5, DMA1_IT_TC5, DMA1_IT_TE5, DMA1_IT_HT5);
}
/*DMA1通道6中断服务程序*/
void DMA1_Channel6_IRQHandler(void)
{
    WHT_DMA_BSP_Channel_IRQHandler(&WHT_DMA1_Channel_6, DMA1_IT_TC6, DMA1_IT_TE6, DMA1_IT_HT6);
}
/*DMA1通道7中断服务程序*/
void DMA1_Channel7_IRQHandler(void)
{
    WHT_DMA_BSP_Channel_IRQHandler(&WHT_DMA1_Channel_7, DMA1_IT_TC7, DMA1_IT_TE7, DMA1_IT_HT7);
}

/*DMA2通道1中断服务程序*/
void DMA2_Channel1_IRQHandler(void)
{
    WHT_DMA_BSP_Channel_IRQHandler(&WHT_DMA2_Channel_1, DMA2_IT_TC1, DMA2_IT_TE1, DMA2_IT_HT1);
}
/*DMA2通道2中断服务程序*/
void DMA2_Channel2_IRQHandler(void)
{
    WHT_DMA_BSP_Channel_IRQHandler(&WHT_DMA2_Channel_2, DMA2_IT_TC2, DMA2_IT_TE2, DMA2_IT_HT2);
}
/*DMA2通道3中断服务程序*/
void DMA2_Channel3_IRQHandler(void)
{
    WHT_DMA_BSP_Channel_IRQHandler(&WHT_DMA2_Channel_3, DMA2_IT_TC3, DMA2_IT_TE3, DMA2_IT_HT3);
}
/*DMA2通道4 5中断服务程序*/
void DMA2_Channel4_5_IRQHandler(void)
{
    if (DMA_GetITStatus(DMA2_IT_GL4) == SET)
    {
        WHT_DMA_BSP_Channel_IRQHandler(&WHT_DMA2_Channel_4, DMA2_IT_TC4, DMA2_IT_TE4, DMA2_IT_HT4);
    }
    if (DMA_GetITStatus(DMA2_IT_GL5) == SET)
    {
        WHT_DMA_BSP_Channel_IRQHandler(&WHT_DMA2_Channel_5, DMA2_IT_TC5, DMA2_IT_TE5, DMA2_IT_HT5);
    }
}
